package analysis.grammaticalAnalysis;

import utils.CommonUtils;

import java.sql.SQLOutput;
import java.util.*;

/**
 * @Author HZ
 * @Date 2022/6/7 17:08
 */
public class GramMain {

    private static final Scanner scan;

    // 文法
    private Map<String, ArrayList<String>> grammarMap;

    // 语法分析开始终结符
    private String startStatus;

    // First集
    Map<String, Set<String>> allFirstSetMap;

    // Follow集
    Map<String, Set<String>> allFollowSetMap;

    // Select集
    Map<String, HashMap<String, Set<String>>> allSelectMap;

    // 是否有进行First集的计算
    private boolean hasCalculateAllFirstSet = false;

    // 是否有进行Follow集的计算
    private boolean hasCalculateAllFollowSet = false;

    // 是否有进行Select集的计算
    private boolean hasCalculateAllSelectMap = false;

    private boolean hasJudgeLL = false;

    // 判断是否是LL(1)文法
    private boolean isLL;

    // LL(1)预测分析表
    private Map<String, Map<String, String>> preParsingTable;

    // 可选字符
    private Set<String> allSelectableCharSet;

    static {
        scan = new Scanner(System.in);
    }

    public GramMain() {
    }

    public GramMain(Map<String, ArrayList<String>> grammarMap, String startStatus) {
        this.grammarMap = grammarMap;
        this.startStatus = startStatus;
    }

    public void gramMain(){
        System.out.println("+-----------------------------------+");
        System.out.println("|-------------语法分析---------------|");
        System.out.println("+-----------------------------------+");
        System.out.println("|-----------1、First集---------------|");
        System.out.println("+-----------------------------------+");
        System.out.println("|-----------2、Follow集--------------|");
        System.out.println("+-----------------------------------+");
        System.out.println("|-----------3、Select集--------------|");
        System.out.println("+-----------------------------------+");
        System.out.println("|-----------4、LL(1)判别-------------|");
        System.out.println("+-----------------------------------+");
        System.out.println("|-----------5、LL(1)分析表-----------|");
        System.out.println("+-----------------------------------+");
        System.out.println("|-----------0、返    回--------------|");
        System.out.println("+-----------------------------------+");

        int itemChoose = -1;
        while (itemChoose != 0){
            System.out.print("\\-> ");
            try{
                itemChoose = Integer.parseInt(scan.next());
                switch (itemChoose){
                    case 0:{
                        System.out.println("|GramMain:gramMain(): 返回中...");
                        return;
                    }
                    case 1:{
                        System.out.println("+-----------------------------------+");
                        System.out.println("|GramMain:gramMain(): calculate FirstSet start...");
                        firstJudge();
                        System.out.println("|GramMain:gramMain(): allFirstSetMap:" + allFirstSetMap);
                        System.out.println("|GramMain:gramMain(): calculate FirstSet finish...");
                        System.out.println("+-----------------------------------+");
                        break;
                    }
                    case 2:{
                        System.out.println("+-----------------------------------+");
                        System.out.println("|GramMain:gramMain(): calculate FollowSet start...");
                        followJudge();
                        System.out.println("|GramMain:gramMain(): allFollowSetMap:" + allFollowSetMap);
                        System.out.println("|GramMain:gramMain(): calculate FollowSet finish...");
                        System.out.println("+-----------------------------------+");
                        break;
                    }
                    case 3:{
                        System.out.println("+-----------------------------------+");
                        System.out.println("|GramMain:gramMain(): calculate SelectMap start...");
                        selectJudge();
                        System.out.println("|GramMain:gramMain(): allSelectMap:" + allSelectMap);
                        System.out.println("|GramMain:gramMain(): calculate SelectMap finish...");
                        System.out.println("+-----------------------------------+");
                        break;
                    }
                    case 4:{
                        System.out.println("|GramMain:gramMain(): LL(1)判别...");
                        LLJudge();
                        if(isLL){
                            System.out.println("|GramMain:gramMain(): 是LL(1)文法...");
                        } else {
                            System.out.println("|GramMain:gramMain(): 不是LL(1)文法...");
                        }
                        System.out.println("+-----------------------------------+");
                        break;
                    }
                    case 5:{
                        System.out.println("|GramMain:gramMain(): LL(1)分析表...");
                        LLJudge();
                        System.out.println("+-----------------------------------+");
                        if(isLL){
                            preParsingTable = createPreParsingTable(allSelectMap);
                            System.out.println("|GramMain:gramMain(): preParsingTable" + preParsingTable);
                            String filePath = "source/test/grammaticalTest/grammarTest6.txt";
                            CommonUtils.printLLPreParsingTableToFile(allSelectableCharSet, preParsingTable, filePath);
                        }else {
                            System.out.println("|GramMain:gramMain(): 不是LL(1)文法，无法生成有效的LL(1)预测分析表...");
                        }
                        System.out.println("+-----------------------------------+");
                        break;
                    }
                    default:{
                        System.out.println("|LexMain:lexMain(): 输入不匹配，请重新输入");
                    }
                }
            } catch (NumberFormatException numberFormatException){
                System.out.println("|LexMain:lexMain(): 输入不匹配，请重新输入");
            } catch (NoSuchElementException noSuchElementException){
                System.out.println("|LexMain:lexMain(): 输入为空");
            }
        }
        scan.close();
    }

    /**
     * 判断是否已经进行了First集求解，如果没有则求解
     */
    private void firstJudge(){
        if( !hasCalculateAllFirstSet ){
            allFirstSetMap = calculateAllFirstSet();
            hasCalculateAllFirstSet = true;
        }
    }

    /**
     * 判断是否已经进行了Follow集求解，如果没有则求解
     */
    private void followJudge(){
        firstJudge();
        if( !hasCalculateAllFollowSet ){
            allFollowSetMap = calculateAllFollowSet();
            hasCalculateAllFollowSet = true;
        }
    }

    /**
     * 判断是否已经进行了Select集求解，如果没有则求解
     */
    private void selectJudge(){
        followJudge();
        if( !hasCalculateAllSelectMap ){
            allSelectMap = calculateAllSelectMap();
            hasCalculateAllSelectMap = true;
        }
    }

    /**
     * 判断是否已经进行了LL(1)的判别，如果没有则求解
     */
    private void LLJudge(){
        selectJudge();
        if( !hasJudgeLL ){
            isLL = judgeIsLL(allSelectMap);
            hasJudgeLL = true;
        }
    }

    /**
     * 计算所有非终结符的First集
     * @return 返回First集
     */
    private Map<String, Set<String>> calculateAllFirstSet(){

        Set<String> notFinalSymbolSet = grammarMap.keySet();    // 非终结符集合

        Map<String, Set<String>> firstSet = new HashMap<>();

        // 初始化所有的first集，遇到非终结符也加入进去
        for(String notFinalSymbol : notFinalSymbolSet){
            getFirstSet(notFinalSymbol, firstSet);
        }
        // 解决First集中终结符问题
        for(String notFinalSymbol : notFinalSymbolSet){
//            System.out.println("|GramMain:calculateAllFirstSet(): firstSet:" + firstSet);
            Set<String> notFinalSymbolFirstSet = firstSet.get(notFinalSymbol);
            Iterator<String> firstStringIterator = notFinalSymbolFirstSet.iterator();
            while (firstStringIterator.hasNext()){
//                System.out.println("|GramMain:calculateAllFirstSet(): notFinalSymbol:" + notFinalSymbol + " notFinalSymbolFirstSet:" + notFinalSymbolFirstSet + " firstSet:" + firstSet);
                String oneOfFirstSetString = firstStringIterator.next();    // 当前key对应的first集中一个元素
                char firstChar = oneOfFirstSetString.charAt(0);
                if(firstChar <= 'Z' && firstChar >= 'A'){   // 解决终结符问题，也就是第四种情况
                    Set<String> currNotFinalSymbolSet;
                    boolean needRemoveNull = false;
                    if (firstSet.containsKey(String.valueOf(firstChar))) {
                        currNotFinalSymbolSet = firstSet.get(String.valueOf(firstChar));
                        if(currNotFinalSymbolSet.contains("ε")){
                            if(oneOfFirstSetString.length() > 1){   // 能推导出空，且产生式右部长度大于1
                                String newFirstString = oneOfFirstSetString.substring(1);
                                notFinalSymbolFirstSet.add(newFirstString);
                                needRemoveNull = true;
                            }
                        }
                    }else {
                        currNotFinalSymbolSet = new HashSet<>();
                        currNotFinalSymbolSet.add("ε");
                    }
                    notFinalSymbolFirstSet.remove(oneOfFirstSetString); // 移除当前已经判断了的开头为非终结符的元素
//                    System.out.println("|notFinalSymbol:" + notFinalSymbol + " currNotFinalSymbolSet:" + currNotFinalSymbolSet + " needRemoveNull:" + needRemoveNull);
                    for(String currNotFinalSymbol : currNotFinalSymbolSet){
                        if( !("ε".equals(currNotFinalSymbol) && needRemoveNull) ){
//                            System.out.println("|currNotFinalSymbol:" + currNotFinalSymbol + " needRemoveNull:" + needRemoveNull);
                            notFinalSymbolFirstSet.add(currNotFinalSymbol);
                        }
                    }
                    firstSet.put(notFinalSymbol, notFinalSymbolFirstSet);

                    firstStringIterator = notFinalSymbolFirstSet.iterator();
//                    System.out.println("|GramMain:calculateAllFirstSet: 重新获取迭代器...");
                }  else if (oneOfFirstSetString.length() > 1 && (firstChar <= 'z' && firstChar >= 'a')){
                    notFinalSymbolFirstSet.add(String.valueOf(firstChar));
                    notFinalSymbolFirstSet.remove(oneOfFirstSetString);
                }
            }
        }

//        System.out.println("|GramMain:calculateAllFirstSet(): firstSet:" + firstSet);

        return firstSet;
    }

    /**
     * 初步获取每个产生式左部对应的非终结符的First集
     * @param notFinalSymbol 产生式左部非终结符
     * @param firstSetMap First集
     */
    private void getFirstSet(String notFinalSymbol, Map<String, Set<String>> firstSetMap){
        ArrayList<String> productionRightList = grammarMap.get(notFinalSymbol);
        for(String productionRight : productionRightList) {
            Set<String> currNotFinalSymbolKeySet;
            if (firstSetMap.containsKey(notFinalSymbol)) {
                currNotFinalSymbolKeySet = firstSetMap.get(notFinalSymbol);
            } else {
                currNotFinalSymbolKeySet = new HashSet<>();
            }
            // 产生式右部为空，或者是ε的情况
            if (productionRight.length() == 0) {
                currNotFinalSymbolKeySet.add("ε");
            } else {
                char firstChar = productionRight.charAt(0);
                if (!(firstChar <= 'Z' && firstChar >= 'A')) {  // 产生式右部开头第一个字符为终结符
                    currNotFinalSymbolKeySet.add(String.valueOf(firstChar));
                } else {    // 产生式右部开头为非终结符
                    currNotFinalSymbolKeySet.add(productionRight);
                }
            }
            firstSetMap.put(notFinalSymbol, currNotFinalSymbolKeySet);
        }
//        System.out.println("|GramMain:getFirst(): notFinalSymbol:" + notFinalSymbol + " firstSet:" + firstSet);
    }

    /**
     * 计算所有非终结符的Follow集
     * @return 返回Follow集
     */
    private Map<String, Set<String>> calculateAllFollowSet(){
        Set<String> notFinalSymbolSet = grammarMap.keySet();    // 非终结符集合

        Map<String, Set<String>> followSet = new HashMap<>();

        // 初始化所有的first集，遇到非终结符也加入进去
        for(String notFinalSymbol : notFinalSymbolSet){
            getFollowSet(notFinalSymbol, followSet);
        }
        System.out.println("|GramMain:calculateAllFollowSet(): firstSet:" + allFirstSetMap);
        System.out.println("|GramMain:calculateAllFollowSet(): followSetStep1:" + followSet);
        System.out.println("|------------------------------------");

        // 先消去follow集中所有出现的开始非终结符
        for(String notFinalSymbol : notFinalSymbolSet){
            Set<String> notFinalSymbolFollowSet = followSet.get(notFinalSymbol);
            if(notFinalSymbolFollowSet.contains(startStatus)){
                notFinalSymbolFollowSet.remove(startStatus);
                notFinalSymbolFollowSet.addAll(followSet.get(startStatus));
                followSet.put(notFinalSymbol, notFinalSymbolFollowSet);
            }
        }
        System.out.println("|GramMain:calculateAllFollowSet(): followSetStep2:" + followSet);
        System.out.println("|------------------------------------");


        // 解决Follow集中终结符问题
        boolean hasContinue = false;
        Iterator<String> notFinalSymbolSetIterator = notFinalSymbolSet.iterator();
        while (notFinalSymbolSetIterator.hasNext()){
            String notFinalSymbol = notFinalSymbolSetIterator.next();
            int count = 0;
//            System.out.println("|GramMain:calculateAllFollowSet(): followSet:" + followSet);
            Set<String> notFinalSymbolFollowSet = followSet.get(notFinalSymbol);
            Iterator<String> followStringIterator = notFinalSymbolFollowSet.iterator();
            while (followStringIterator.hasNext()){
                if(count < 100){
//                    System.out.println("|GramMain:calculateAllFollowSet(): notFinalSymbol:" + notFinalSymbol + " notFinalSymbolFollowSet:" + notFinalSymbolFollowSet + " followSet:" + followSet);
                    String oneOfFollowSetString = followStringIterator.next();    // 当前key对应的first集中一个元素
                    char followChar = oneOfFollowSetString.charAt(0);
                    if(followChar <= 'Z' && followChar >= 'A'){   // 解决终结符问题，也就是第四种情况
                        Set<String> currNotFinalSymbolSet;
                        if (followSet.containsKey(oneOfFollowSetString)) {
                            currNotFinalSymbolSet = followSet.get(oneOfFollowSetString);

                            notFinalSymbolFollowSet.remove(oneOfFollowSetString); // 移除当前已经判断了的开头为非终结符的元素
//                    System.out.println("|notFinalSymbol:" + notFinalSymbol + " currNotFinalSymbolSet:" + currNotFinalSymbolSet + " needRemoveNull:" + needRemoveNull);
                            notFinalSymbolFollowSet.addAll(currNotFinalSymbolSet);
                            followSet.put(notFinalSymbol, notFinalSymbolFollowSet);

                            followStringIterator = notFinalSymbolFollowSet.iterator();
//                    System.out.println("|GramMain:calculateAllFirstSet: 重新获取迭代器...");
                        }
                    }
                    count++;
                }else {
                    hasContinue = true;
                    break;
                }
            }
            if( !notFinalSymbolSetIterator.hasNext() && hasContinue ){  // 当现在存在跳过的行为，且已经遍历到末尾，就重开一次
                hasContinue = false;
                notFinalSymbolSetIterator = notFinalSymbolSet.iterator();
            }
        }

        System.out.println("|GramMain:calculateAllFollowSet(): followSetStep3:" + followSet);
        System.out.println("|------------------------------------");

        return followSet;
    }

    /**
     * 计算单个非终结符的Follow集
     * @param notFinalSymbol 待计算的非终结符
     * @param followSetMap 当前已经计算得出的Follow集合
     */
    private void getFollowSet(String notFinalSymbol, Map<String, Set<String>> followSetMap){
        if(startStatus.equals(notFinalSymbol)){     // 如果当前非终结符是开始状态，则设置 #
            Set<String> startNotFinalSymbol = new HashSet<>();
            startNotFinalSymbol.add("#");
            followSetMap.put(notFinalSymbol, startNotFinalSymbol);
        }
        // 找出所有包含该非终结符的产生式右部
        Map<String, ArrayList<String>> currNotFinalSymbolFollowMap = new HashMap<>();
        Set<String> productionLeftSet = grammarMap.keySet();
        for(String productionLeft : productionLeftSet) {
            ArrayList<String> productionRightList = grammarMap.get(productionLeft);
            for(String productionRight : productionRightList){
                if(productionRight.contains(notFinalSymbol)){
                    ArrayList<String> productionRightMapLeft;
                    if(currNotFinalSymbolFollowMap.containsKey(productionRight)){
                        productionRightMapLeft = currNotFinalSymbolFollowMap.get(productionRight);
                    }else {
                        productionRightMapLeft = new ArrayList<>();
                    }
                    productionRightMapLeft.add(productionLeft);
                    currNotFinalSymbolFollowMap.put(productionRight, productionRightMapLeft);
                }
            }
        }
//        System.out.println("|GramMain:getFollowSet(): notFinalSymbol:" + notFinalSymbol);
//        System.out.println("|GramMain:getFollowSet(): currNotFinalSymbolFollowMap:" + currNotFinalSymbolFollowMap);

        // 初始化当前非终结符的follow集
        Set<String> currNotFinalSymbolFollowSet;
        if(followSetMap.containsKey(notFinalSymbol)) {
            currNotFinalSymbolFollowSet = followSetMap.get(notFinalSymbol);
        }else {
            currNotFinalSymbolFollowSet = new HashSet<>();
        }
        // 开始对该非终结符右边的部分进行判断
        Set<String> notFinalSymbolProductionRightSet = currNotFinalSymbolFollowMap.keySet();
        char notFinalSymbolChar = notFinalSymbol.charAt(0);
        for(String notFinalSymbolFound : notFinalSymbolProductionRightSet){
            int notFinalSymbolFoundLen = notFinalSymbolFound.length();
            int notFinalSymbolIndex = notFinalSymbolFound.indexOf(notFinalSymbolChar);
            int point = notFinalSymbolIndex + 1;
            if(point == notFinalSymbolFoundLen){    // 当前非终结符位于末尾
                List<String> notFinalSymbolFoundLeftList = new ArrayList<>(currNotFinalSymbolFollowMap.get(notFinalSymbolFound));
                currNotFinalSymbolFollowSet.addAll(notFinalSymbolFoundLeftList);
            }
            while(point < notFinalSymbolFoundLen){
                char toBeJudgeChar = notFinalSymbolFound.charAt(point);
                if (toBeJudgeChar <= 'Z' && toBeJudgeChar >= 'A'){
//                    System.out.println("|here1......... toBeJudgeChar:" + toBeJudgeChar + " allFirstSetMap:" + allFirstSetMap);
                    if(allFirstSetMap.containsKey(String.valueOf(toBeJudgeChar))){
//                        System.out.println("|here2.........");
                        Set<String> toBeJudgeCharFirstSet = allFirstSetMap.get(String.valueOf(toBeJudgeChar));
                        if(toBeJudgeCharFirstSet.contains("ε")){    // 包含ε
//                            System.out.println("|here3.........");
                            for(String toBeJudgeCharFirstSetValue : toBeJudgeCharFirstSet){
                                if(!"ε".equals(toBeJudgeCharFirstSetValue)){    // 除去ε
//                                    System.out.println("|here4.........");
                                    currNotFinalSymbolFollowSet.add(toBeJudgeCharFirstSetValue);
                                }
                            }
                        } else {    // 不包含ε，则在添加这个非终结符的first集之后直接跳到下一个
//                            System.out.println("|here5.........");
                            currNotFinalSymbolFollowSet.addAll(toBeJudgeCharFirstSet);
                            break;
                        }
                    }
                    if(point == notFinalSymbolFoundLen - 1){    // 当前符号是终结符，其是该产生式的最后一个字符
//                        System.out.println("|here6.........");
                        currNotFinalSymbolFollowSet.addAll(currNotFinalSymbolFollowMap.get(notFinalSymbolFound));
                    }
                    point++;
                }else{  // 当前已经检索到终结符
//                    System.out.println("|here7.........");
                    currNotFinalSymbolFollowSet.add(String.valueOf(toBeJudgeChar));
                    break;
                }
            }
        }
        followSetMap.put(notFinalSymbol, currNotFinalSymbolFollowSet);
//        System.out.println("|GramMain:getFollowSet(): followSet:" + followSet);
//        System.out.println("+-----------------------------------+");
    }

    /**
     * 计算所有非终结符的Select集，前提是已经计算出Follow集和First集
     * @return 返回所有产生式的Select集
     */
    private Map<String, HashMap<String, Set<String>>> calculateAllSelectMap(){

        Set<String> notFinalSymbolSet = grammarMap.keySet();    // 非终结符集合

        Map<String, HashMap<String, Set<String>>> selectMap = new HashMap<>();

        // 初始化所有的first集，遇到非终结符也加入进去
        for(String notFinalSymbol : notFinalSymbolSet){
            ArrayList<String> productionRightList = grammarMap.get(notFinalSymbol);
            for(String productionRight : productionRightList){
                getSelectSet(notFinalSymbol, productionRight, selectMap);
            }
        }
        System.out.println("|GramMain:calculateAllSelectMap(): selectMap:" + selectMap);
        System.out.println("+-----------------------------------+");

        return selectMap;
    }

    /**
     * 单个计算每个产生式的Select集
     * @param productionLeft 产生式左部
     * @param productionRight 产生式右部
     * @param selectMap 已计算出来的Select集
     */
    private void getSelectSet(String productionLeft, String productionRight, Map<String, HashMap<String, Set<String>>> selectMap){
        System.out.println("|GramMain:getSelectSet(): productionLeft:" + productionLeft + " productionRight:" + productionRight + " selectMap:" + selectMap);
        Set<String> currSelectSet = new HashSet<>();
        int productionRightLen = productionRight.length();
        // 产生式右部长度为0，或者产生式右部为ε字符
        if(productionRightLen == 0 ||( productionRightLen == 1 && "ε".equals(productionRight))){
            if(allFollowSetMap.containsKey(productionLeft)){
                currSelectSet.addAll(allFollowSetMap.get(productionLeft));
            }
        }
        for(int i = 0; i < productionRightLen; i++){
            char toBeJudgeChar = productionRight.charAt(i);
            if(toBeJudgeChar <= 'Z' && toBeJudgeChar >= 'A'){
                Set<String> toBeJudgeCharFollowSet;
                toBeJudgeCharFollowSet =  allFirstSetMap.get(String.valueOf(toBeJudgeChar));
                if(toBeJudgeCharFollowSet.contains("ε")){   // 当前判断的字符包含ε
                    if(i == productionRightLen - 1){    // 扫描到末尾，并且最后一个字符还为非终结符，可以推出ε
                        currSelectSet.addAll(allFollowSetMap.get(productionLeft));
                    }
                }
                if (toBeJudgeCharFollowSet.contains("ε")){
                    for(String toBeJudgeCharFollowString : toBeJudgeCharFollowSet){
                        if( !"ε".equals(toBeJudgeCharFollowString) ){   // 移除First集中的ε
                            currSelectSet.add(toBeJudgeCharFollowString);
                        }
                    }
                } else {
                    currSelectSet.addAll(toBeJudgeCharFollowSet);
                    break;
                }
            } else{
                currSelectSet.add(String.valueOf(toBeJudgeChar));
                break;
            }
        }
        HashMap<String, Set<String>> tmpMap;
        if(selectMap.containsKey(productionLeft)){
            tmpMap = selectMap.get(productionLeft);
        }else {
            tmpMap = new HashMap<>();
        }
        currSelectSet.remove("ε");
        tmpMap.put(productionRight, currSelectSet);
        selectMap.put(productionLeft, tmpMap);
    }

    /**
     * 判断是否是LL(1)文法，前提是已经计算出Select集
     * @param selectMap 已经计算出来的所有产生式的Select集
     * @return 返回判别结果，ture:表示是LL(1)文法，false:表示不是LL(1)文法
     */
    private boolean judgeIsLL(Map<String, HashMap<String, Set<String>>> selectMap){
        Set<String> productionLeftSet = selectMap.keySet();
        for(String productionLeft : productionLeftSet){
            HashMap<String, Set<String>> productionRightMap = selectMap.get(productionLeft);
            if(productionRightMap.size() < 2){
                continue;
            }
            Set<String> productionRightSet = productionRightMap.keySet();
            Set<String> currProductionLeftAllSelectSet = new HashSet<>();
            for(String productionRight : productionRightSet){
                Set<String> currProductionLeftSelect = productionRightMap.get(productionRight);
                for(String currProductionLeftSelectElement : currProductionLeftSelect){
                    if(currProductionLeftAllSelectSet.contains(currProductionLeftSelectElement)){
                        System.out.println("|GramMain:judgeIsLL(): currProductionLeftAllSelectSet:" + currProductionLeftAllSelectSet);
                        System.out.println("|GramMain:judgeIsLL(): currProductionLeftSelect:" + currProductionLeftSelect);
                        return false;
                    }
                }
                currProductionLeftAllSelectSet.addAll(currProductionLeftSelect);
            }
        }
        return true;
    }

    /**
     * 生成LL(1)文法预测分析表
     * @param selectMap
     * @return
     */
    private Map<String, Map<String, String>> createPreParsingTable(Map<String, HashMap<String, Set<String>>> selectMap){
        if(selectMap.size() == 0){
            return null;
        }
        Map<String, Map<String, String>> retPreParsingTable = new HashMap<>();
        // 获取所有的可选字符
        allSelectableCharSet = new HashSet<>();
        Set<String> productionLeftSet = selectMap.keySet();
        for(String productionLeft : productionLeftSet){
            Map<String, Set<String>> productionRightMap = selectMap.get(productionLeft);
            Set<String> productionRightSet = productionRightMap.keySet();
            for(String productionRight : productionRightSet){
                Set<String> selectCharSet = productionRightMap.get(productionRight);
                allSelectableCharSet.addAll(selectCharSet);
            }
        }
        System.out.println("|GramMain:createPreParsingTable(): allSelectableCharSet:" + allSelectableCharSet);

        // 将Select集解析到LL(1)分析表里面
        for(String productionLeft : productionLeftSet){
            Map<String, Set<String>> productionRightMap = selectMap.get(productionLeft);
            Set<String> productionRightSet = productionRightMap.keySet();
            Map<String, String> llPreChooseItem = new HashMap<>();
            for(String productionRight : productionRightSet){
                Set<String> selectCharSet = productionRightMap.get(productionRight);
                String production = productionLeft + "→" + productionRight;
                for(String selectChar : selectCharSet){
                    llPreChooseItem.put(selectChar, production);
                }
            }
            retPreParsingTable.put(productionLeft, llPreChooseItem);
        }

        // 将没有出现在预测分析表里面的，设置为不可达状态，也就是^
        for(String productionLeft : productionLeftSet) {
            Map<String, String> productionRightMap = retPreParsingTable.get(productionLeft);
            for(String selectChar : allSelectableCharSet){
                if(!productionRightMap.containsKey(selectChar)){
                    productionRightMap.put(selectChar, "^");
                }
            }
            retPreParsingTable.put(productionLeft, productionRightMap);
        }

        return retPreParsingTable;
    }
}
